package com.wq.gamesnack.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;


import java.util.LinkedList;

/**
 * 贪食蛇-游戏视图
 * Created by WQ on 2018/4/12.
 */

public class SnackGameView extends View {
    /**
     * 蛇头方向
     */
    public final static int S_LEFT = 0;
    public final static int S_TOP = 1;
    public final static int S_RIGHT = 2;
    public final static int S_BOTTOM = 3;
    public final static int S_BASE_SPEED = 300;
    int mColNum = 18;//列数
    int mRowNum = 18;//列数
    float mColWidth;//列宽

    int mBgColor = Color.parseColor("#a7a6ab");//背景颜色
    int mGridLineColor = Color.parseColor("#838692");//网格线颜色
    int mSnackBodyColor = Color.WHITE;//蛇身颜色
    int mSnackHeadColor = Color.WHITE;//蛇头颜色
    int mFoodColor = Color.parseColor("#fcae14");//食物颜色
    int mSnackDefLen = 3;//蛇身默认长度
    int mDirec = S_LEFT;//蛇头方向
    int mSpeed = S_BASE_SPEED;//移动速度
    int mQuickSpeed = 50;//快速移动时的速度
    boolean mIsQuickMove = false;//是否快速移动
    boolean mGamePause = false;
    Paint mPaint;
    LinkedList<SnackBody> mSnackBodys = new LinkedList<>();
    SnackBody mFood = new SnackBody(0, 0);
    OnEatFoodListener onEatFoodListener;
    OnGameOverListener onGameOverListener;

    public SnackGameView(Context context) {
        super(context);
        initView();
    }


    public SnackGameView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initView();
    }


    public SnackGameView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    private void initView() {
        mPaint = new Paint();
//        mPaint.setStrokeWidth(1);
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        post(new Runnable() {
            @Override
            public void run() {
                initGame();
            }
        });
    }

    public void initGame() {
        mGamePause = false;
        mIsQuickMove = false;
        mSpeed = S_BASE_SPEED;
        mSnackDefLen = 3;
        mDirec = S_LEFT;
        mColWidth = (float) (1f*getWidth() / mColNum );//计算格子大小
        mRowNum = (int) (1f*getHeight() / mColWidth);//计算行数
        //在中间放置身体
        LinkedList<SnackBody> mSnackBodys = this.mSnackBodys;
        mSnackBodys.clear();
        for (int i = 0; i < mSnackDefLen; i++) {
            mSnackBodys.addLast(new SnackBody(mColNum / 2 - (mSnackDefLen / 2 - i), mRowNum / 2));
        }

        if(isInEditMode())return;//
        randomFood();
        beginGameRun();
    }

    Runnable runnable;

    private void beginGameRun() {
        removeCallbacks(runnable);
        final Runnable localRun = new Runnable() {
            @Override
            public void run() {
                int speed = mIsQuickMove ? mQuickSpeed : mSpeed;
                snackMove();
                invalidate();
                postDelayed(runnable, speed);
            }
        };
        postDelayed(this.runnable = localRun, mSpeed);
    }

    //随机食物
    private void randomFood() {
        LinkedList<SnackBody> mSnackBodys = this.mSnackBodys;
        if (mSnackBodys.size() >= mColNum * mRowNum) {
            return;//满了,这么吊的么
        }
        SnackBody first = mSnackBodys.getFirst();
        SnackBody food = new SnackBody(0, 0);
        do {
            food.setPositon(random(0, mColNum), random(0, mRowNum));
        } while (first.equals(food));
        this.mFood = food;
    }

    public int random(int min, int max) {
        return (int) (Math.random() * (max - min) + min);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(mBgColor);
        drawFood(canvas);
        drawSnack(canvas);
        drawGridBg(canvas);
    }

    /**
     * 绘制网格背景
     * @param canvas
     */
    private void drawGridBg(Canvas canvas) {
        int colNum = this.mColNum;
        int rowNum = (int) (getHeight() / mColWidth);//计算行数
        //绘制网格
        mPaint.setColor(mGridLineColor);
        //绘制列
        for (int i = 0; i <= colNum; i++) {
            float startX = i * mColWidth;
            canvas.drawLine(startX, 0, startX, getHeight(), mPaint);
        }
        //绘制行
        for (int i = 0; i <= rowNum; i++) {
            float startY = i * mColWidth;
            canvas.drawLine(0, startY, getWidth(), startY, mPaint);
        }
    }

    /**
     * 绘制蛇
     * @param canvas
     */
    private void drawSnack(Canvas canvas) {
        LinkedList<SnackBody> mSnackBodys = this.mSnackBodys;
        for (int i = mSnackBodys.size() - 1; i >= 0; i--) {
            SnackBody mSnackBody = mSnackBodys.get(i);
            mPaint.setColor(i == 0 ? mSnackHeadColor : mSnackBodyColor);
            float left = mSnackBody.x * mColWidth;
            float top = mSnackBody.y * mColWidth;
            canvas.drawRect(left, top, left + mColWidth, top + mColWidth, mPaint);
        }
    }

    /**
     * 绘制食物
     * @param canvas
     */
    private void drawFood(Canvas canvas) {
        SnackBody mFood = this.mFood;
        mPaint.setColor(mFoodColor);
        float left = mFood.x * mColWidth;
        float top = mFood.y * mColWidth;
        canvas.drawRect(left, top, left + mColWidth, top + mColWidth, mPaint);
    }

    /**
     * 蛇的移动
     */
    private void snackMove() {
        if (mGamePause) return;
        LinkedList<SnackBody> mSnackBodys = this.mSnackBodys;
        SnackBody nextHead = new SnackBody(0, 0);
        SnackBody snackHead = mSnackBodys.getFirst();
        switch (mDirec) {
            case S_LEFT:
                nextHead.setPositon(snackHead.x - 1, snackHead.y);
                break;
            case S_TOP:
                nextHead.setPositon(snackHead.x, snackHead.y - 1);
                break;
            case S_RIGHT:
                nextHead.setPositon(snackHead.x + 1, snackHead.y);
                break;
            case S_BOTTOM:
                nextHead.setPositon(snackHead.x, snackHead.y + 1);
                break;
        }
        mSnackBodys.addFirst(nextHead);
        mSnackBodys.removeLast();
        //检查是否吃到食物了,
        SnackBody mFood = this.mFood;
        if (nextHead.equals(mFood)) {
            mSnackBodys.addFirst(mFood);
            mSpeed = getSpeed();//计算新速度
            if (onEatFoodListener != null) {
                onEatFoodListener.eatFood(mSpeed);
            }
            //追加到头部,重新随机食物
            randomFood();
        }
        checkGameEnd();
    }

    private void checkGameEnd() {
        LinkedList<SnackBody> mSnackBodys = this.mSnackBodys;
        SnackBody headBody = mSnackBodys.getFirst();
        //查询头部与身体的交集
        int indexOf = mSnackBodys.lastIndexOf(headBody);
        int cellNum = mColNum * mRowNum;
        int snackLen = mSnackBodys.size();
        //边界判断,咬到自己的判断,和占满了
        if (headBody.x < 0 ||
                headBody.y < 0 ||
                headBody.x >= mColNum ||
                headBody.y >= mRowNum ||
                //0 是蛇头 1是刚吃到的食物 不可能咬到脖子(第二格)
                (indexOf != 0 &&indexOf != 1 && indexOf != -1)||
                    snackLen>=cellNum
                ) {
            mGamePause = true;
            if (onGameOverListener != null) {
                onGameOverListener.gameOver(snackLen, cellNum);
            }
        }
    }

    public void turnTo(int direc) {
        switch (direc) {
            case S_LEFT:
                if (mDirec != S_RIGHT) {
                    mDirec = direc;
                }
                break;
            case S_TOP:
                if (mDirec != S_BOTTOM) {
                    mDirec = direc;
                }
                break;
            case S_RIGHT:
                if (mDirec != S_LEFT) {
                    mDirec = direc;
                }
                break;
            case S_BOTTOM:
                if (mDirec != S_TOP) {
                    mDirec = direc;
                }
                break;
        }
        beginGameRun();
        snackMove();
        invalidate();
    }

    public int getSpeed() {
        int size = mSnackBodys.size();
        float percent = 1 - size / (mColNum * mRowNum);
        float newSpeed = 300 * percent;
        return (int) newSpeed;
    }

    public void setOnEatFoodListener(OnEatFoodListener onEatFoodListener) {
        this.onEatFoodListener = onEatFoodListener;
    }

    public void setOnGameOverListener(OnGameOverListener onGameOverListener) {
        this.onGameOverListener = onGameOverListener;
    }

    public interface OnEatFoodListener {
        void eatFood(int speed);
    }

    public interface OnGameOverListener {
        void gameOver(int snackLen, int cellNum);
    }

    @Override
    protected void onDetachedFromWindow() {
        removeCallbacks(runnable);
        super.onDetachedFromWindow();

    }
    protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        mGamePause = visibility != VISIBLE;
    }
    class SnackBody {
        public int x, y;//坐标

        public void setPositon(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public SnackBody(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            SnackBody snackBody = (SnackBody) o;
            if (x != snackBody.x) return false;
            return y == snackBody.y;
        }

        @Override
        public int hashCode() {
            int result = x;
            result = 31 * result + y;
            return result;
        }
    }
}
